package cn.nkpro.elcube.cloud.idds;

import cn.nkpro.elcube.cloud.NkCloudProperties;
import cn.nkpro.elcube.exception.NkSystemException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class NkCloudIddsClient {

    private NkCloudProperties cloudProperties;

    private RestHighLevelClient client;


    public NkCloudIddsClient(NkCloudProperties cloudProperties) {

        this.cloudProperties = cloudProperties;

        HttpHost[] httpHosts = cloudProperties.getIdds().getUris().stream().map(x -> {
            String[] i = x.split("[:]");
            String hostname = i[1].substring(2);
            int port = Integer.parseInt(i[2]);
            String scheme = i[0];
            return new HttpHost(hostname,port,scheme);
        }).toArray(HttpHost[]::new);

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials(
                        cloudProperties.getIdds().getUsername(),
                        cloudProperties.getIdds().getPassword()
                )
        );

        RestClientBuilder builder = RestClient.builder(httpHosts)
                .setHttpClientConfigCallback(httpAsyncClientBuilder ->
                        httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                );

        this.client = new RestHighLevelClient(builder);

        this.find("1");
    }

    public void push(String objectId, String producer){

        ID id = new ID();
        id.setObjectId(objectId);
        id.setProducerId(producer);

        try {
            client.index(new IndexRequest(
                                cloudProperties.getIdds().getName()
                            )
                            .id(String.format("%s@%s",objectId,cloudProperties.getId()))
                            .source((JSONObject)JSON.toJSON(id)),
                    RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new NkSystemException("IDDS服务发生错误："+e.getMessage(), e);
        }
    }

    public List<ID> find(String objectId){
        try {
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                    .postFilter(
                            QueryBuilders.termQuery("objectId",objectId)
                    )
                    .timeout(new TimeValue(10, TimeUnit.SECONDS));

            SearchRequest searchRequest = new SearchRequest()
                    .indices(cloudProperties.getIdds().getName())
                    .source(sourceBuilder);

            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            return Arrays.stream(hits)
                    .map(ID::parse)
                    .collect(Collectors.toList());

        } catch (IOException e) {
            throw new NkSystemException("搜索引擎发生错误："+e.getMessage(), e);
        }
    }

    @Data
    public static class ID{
        String id;
        String objectId;
        String producerId;

        static ID parse(SearchHit hit){
            ID id = new JSONObject(hit.getSourceAsMap()).toJavaObject(ID.class);
            id.setId(hit.getId());
            return id;
        }
    }
}
